package main

import (
	"context"
	"github.com/micro/go-micro/v2"
	"github.com/micro/go-micro/v2/broker"
	"github.com/micro/go-micro/v2/broker/nats"
	"github.com/micro/go-micro/v2/registry"
	"github.com/micro/go-micro/v2/registry/etcd"
	"github.com/micro/go-plugins/wrapper/trace/opentracing/v2"
	"github.com/pkg/errors"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
	"go.mongodb.org/mongo-driver/mongo/readpref"
	"log"
	"time"
	"todolist/common/tracer"
	"todolist/task-srv/handler"
	pb "todolist/task-srv/proto/task"
	"todolist/task-srv/repository"
)

// 在main.go中注册服务
// 在v2版本中go-micro默认使用mdns作为服务发现，无需安装部署主要用于学习和简单场景开发，
// 生产环境官方建议使用etcd
// 另外，由于本服务暂时没有需要处理的消息，我们删除了消息相关接口。

const (
	MONGO_URI  = "mongodb://june:june123@139.155.239.206:27017/todolist"
	ServerName = "go.micro.service.task"
	JaegerAddr = "139.155.239.206:6831"
)

func main() {
	// 在日志中打印文件路径
	log.SetFlags(log.Llongfile)
	conn, err := connectMongo(MONGO_URI, time.Second)
	if err != nil {
		log.Fatal(err)
	}
	defer conn.Disconnect(context.Background())
	log.Println("connect to mongodb success!")

	// 配置Jaeger连接
	jaegerTracer, closer, err := tracer.NewJaegerTracer(ServerName, JaegerAddr)
	if err != nil {
		log.Fatal(err)
	}
	defer closer.Close()

	// 建立新的服务
	service := micro.NewService(
		micro.Name(ServerName),
		micro.Version("latest"),
		// 配置etcd为注册中心，etcd默认端口是2379,此时启动程序，服务已经注册到了etcd中
		micro.Registry(etcd.NewRegistry(
			registry.Addrs("139.155.239.206:2379"),
		)),
		// 新增消息中间件nats
		micro.Broker(nats.NewBroker(
			broker.Addrs("nats://139.155.239.206:4222"),
		)),

		// 新增链路追踪，WrapHandler() server中间件
		micro.WrapHandler(
			opentracing.NewHandlerWrapper(jaegerTracer),
		),
	)

	// 初始化服务
	service.Init()

	// 注册handler，来源于handler中的TaskHandler
	taskHandler := &handler.TaskHandler{
		// TaskHandler中只有一个变量TaskRepository，它来源于repository
		// 其实现为TaskRepositoryImpl，其中包含了一个*mongo.Client
		TaskRepository: &repository.TaskRepositoryImpl{
			Conn: conn,
		},
		// 注入消息发送实例,为避免消息名冲突,这里的topic我们用服务名+自定义消息名拼出
		TaskFinishedPubEvent: micro.NewEvent("go.micro.service."+handler.TaskFinishedTopic, service.Client()),
	}
	err = pb.RegisterTaskServiceHandler(service.Server(), taskHandler)
	if err != nil {
		log.Fatal(errors.WithMessage(err, "register service"))
	}

	// 启动服务
	if err = service.Run(); err != nil {
		log.Fatal(errors.WithMessage(err, "run server"))
	}
}

func connectMongo(uri string, timeout time.Duration) (*mongo.Client, error) {
	ctx, cancel := context.WithTimeout(context.Background(), timeout)
	defer cancel()
	// Connect 不保证返回的连接有效
	client, err := mongo.Connect(ctx, options.Client().ApplyURI(uri))
	if err != nil {
		return nil, errors.WithMessage(err, "failed to connect with mongo db")
	}

	if err = client.Ping(ctx, readpref.Primary()); err != nil {
		return nil, errors.WithMessage(err, "client.Ping failed")
	}

	return client, nil
}
